package ch.usi.inf.pf2.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

import ch.usi.inf.pf2.Sheet;
import ch.usi.inf.pf2.cell.Data;
import ch.usi.inf.pf2.editor.UndoRedoStack;
import ch.usi.inf.pf2.gui.listener.CloseActionListener;
import ch.usi.inf.pf2.gui.listener.CopyActionListener;
import ch.usi.inf.pf2.gui.listener.CutActionListener;
import ch.usi.inf.pf2.gui.listener.PasteActionListener;
import ch.usi.inf.pf2.gui.listener.RedoActionListener;
import ch.usi.inf.pf2.gui.listener.UndoActionListener;

/**
 * This class is responsible of creating the entire GUI of the SpreadSheet
 * 
 * @author Thomas Mantegazzi, Yotam Sharon, Lorenzo Baracchi, Ebrisa Savina
 *         Mastrodicasa
 * 
 */

public class JSpreadSheetGUI {

	private JFrame frame;
	private Sheet sheet;
	private JTable table;
	private JTextField textField;
	private UndoRedoStack stack;
	private JSpreadSheetGUI spreadTable;

	
	/**
	 * Constructor for the class, without arguments
	 */
	public JSpreadSheetGUI() {
		System.out.println("GUI started");
		sheet = new Sheet();
		sheet.initializeSheet();
		stack = new UndoRedoStack();
		spreadTable = this;
		makeFrame();
	}

	/**
	 * Constructor that create a JSpreadSheetGUI object for the given Sheet
	 * @param sheet The sheet we want to represent with this GUI
	 */
	public JSpreadSheetGUI(Sheet sheet) {
		System.out.println("GUI started");
		this.sheet = sheet;
		sheet.initializeSheet();
		stack = new UndoRedoStack();
		makeFrame();
	}

	/**
	 * Initialize the frame
	 */
	public void makeFrame() {
	/*
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (ClassNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (InstantiationException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IllegalAccessException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (UnsupportedLookAndFeelException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}*/
	
		frame = new JFrame("SpreadSheet - " + sheet.getName());
		frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		frame.addWindowListener(new WindowListener() {

			@Override
			public void windowOpened(WindowEvent e) {
				// TODO Auto-generated method stub
			}

			@Override
			public void windowIconified(WindowEvent e) {
				// TODO Auto-generated method stub
			}

			@Override
			public void windowDeiconified(WindowEvent e) {
				// TODO Auto-generated method stub
			}

			@Override
			public void windowDeactivated(WindowEvent e) {
				// TODO Auto-generated method stub
				System.out.println("Window deactivated");
			}

			@Override
			public void windowClosing(WindowEvent e) {
				System.out.println("Window closing");
				CloseActionListener closeAl = new CloseActionListener(spreadTable);
				closeAl.actionPerformed(null);
				
			}

			@Override
			public void windowClosed(WindowEvent e) {
				System.out.println("Window closed");
			}

			@Override
			public void windowActivated(WindowEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
		// making the panel
		makePanel();
		// making the menu
		makeMenu();

		frame.pack();
		// setting the Frame visible
		frame.setVisible(true);
	}

	
	
	/**
	 * Create the menu bar
	 */
	public void makeMenu() {

		JSpreadSheetMenu menu = new JSpreadSheetMenu(this);
		frame.setJMenuBar(menu.getMenubar());
		menu.makeMenus();
	}

	
	
	/**
	 * Create the content pane
	 */
	public void makePanel() {
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new BorderLayout(3, 3));
		
		JLabel statusLabel = new JLabel("  ");
		JPanel downPane = new JPanel(new BorderLayout());
		downPane.add(statusLabel);

		// create borders
		JPanel upPane = new JPanel(new BorderLayout());
		textField = new JTextField();
		upPane.add(textField, BorderLayout.SOUTH);
		SpreadSheetToolbar toolBar = new SpreadSheetToolbar(this);
		toolBar.makeToolBar();
		upPane.add(toolBar, BorderLayout.CENTER);
		contentPane.add(upPane, BorderLayout.NORTH);
		contentPane.add(downPane, BorderLayout.SOUTH);
		contentPane.add(new JPanel(), BorderLayout.EAST);
		contentPane.add(new JPanel(), BorderLayout.WEST);

		// A JTextField used from the JSpreadSheetCellEditor to edit cells
		final JTextField cellEditor = new JTextField();
		cellEditor.setBounds(textField.getX(), textField.getY(), textField
				.getWidth(), 5);
		cellEditor.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
					cellEditor.grabFocus();
					textField.setText(cellEditor.getText());
					System.out.println(cellEditor.getText());	
			}

			@Override
			public void keyPressed(KeyEvent e) {
			}	
		});

		// ********Creating the Table*********//

		// getting the column names and the data of the table
		String[] columnNames = getColumnNames();
		Object[][] data = sheet.getGridWithoutHeaders();

		// creating a SpreadSheetTableModel
		SpreadSheetTableModel tableModel = new SpreadSheetTableModel(
				columnNames, data, sheet, stack);

		// Creating a JTable with the previously created SpreadSheetTableModel
		final JTable table = new JTable(tableModel);
		this.table = table;
		table.setRowHeight(tableModel.getDefaultRowHight());
		table.setDefaultRenderer(Data.class, new DataRenderer(textField,
				cellEditor, statusLabel));
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.setGridColor(new Color(187, 184, 178));
		table.setDragEnabled(false);
		table.setRowSelectionAllowed(false);
		table.setCellSelectionEnabled(true);
		table.setDefaultEditor(Data.class, new JSpreadSheetCellEditor(
				cellEditor, table));

		table.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				manageShortcuts(e);
				int c = table.getSelectedColumn();
				int r = table.getSelectedRow();
				//table.editCellAt(r, c, e);
				//cellEditor.grabFocus();
				if(e.getKeyCode() == KeyEvent.VK_ESCAPE || e.getKeyCode() == KeyEvent.VK_ENTER) {
					table.setRowHeight(r, ((SpreadSheetTableModel)table.getModel()).getDefaultRowHight());
				}else {
					table.editCellAt(r, c, e);
					cellEditor.grabFocus();
					System.out.println(e.getKeyChar());
				}

			}

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub

			}
			
			private boolean manageShortcuts (KeyEvent e)
			{
				if(e.getKeyCode() == KeyEvent.VK_Z && e.isMetaDown())
				{
					UndoActionListener ual = new UndoActionListener(spreadTable);
					ual.actionPerformed(null);
					System.out.println("undo");
					return true;
				}
				if(e.getKeyCode() == KeyEvent.VK_R && e.isMetaDown())
				{
					RedoActionListener ral = new RedoActionListener(spreadTable);
					ral.actionPerformed(null);
					return true;
				}
				if(e.getKeyCode() == KeyEvent.VK_X && e.isMetaDown())
				{
					CutActionListener cutAl = new CutActionListener(spreadTable);
					cutAl.actionPerformed(null);
					return true;
				}
				if(e.getKeyCode() == KeyEvent.VK_C && e.isMetaDown())
				{
					CopyActionListener copyAl = new CopyActionListener(spreadTable);
					copyAl.actionPerformed(null);
					System.out.println("Copy");
					return true;
				}
				if(e.getKeyCode() == KeyEvent.VK_V && e.isMetaDown())
				{
					PasteActionListener pal = new PasteActionListener(spreadTable);
					pal.actionPerformed(null);
					System.out.println("Paste");
					return true;
				}
				if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					e.consume();
					return false;
				}
				return false;
			}
		});

		table.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e)
			{
				if(e.isPopupTrigger())
				{
					JSpreadSheetPopupMenu popup = new JSpreadSheetPopupMenu(spreadTable);
					popup.show(frame, e.getX(), e.getY()+75);
				}
			}
			
			public void mouseReleased(MouseEvent e)
			{
				if(e.isPopupTrigger())
				{
					JSpreadSheetPopupMenu popup = new JSpreadSheetPopupMenu(spreadTable);
					popup.show(table, e.getX(), e.getY()+75);
				}
			}
		});
		
		textField.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				int c = table.getSelectedColumn();
				int r = table.getSelectedRow();
				table.getModel().setValueAt(textField.getText(), r, c);
				((JSpreadSheetCellEditor) table.getDefaultEditor(Data.class))
				.stopCellEditing();
				table.grabFocus();
			}
		});
		textField.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				int c = table.getSelectedColumn();
				int r = table.getSelectedRow();
				table.editCellAt(r, c, e);
				cellEditor.setText(textField.getText());
				System.out.println(textField.getText());

			}

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub

			}
		});

		// creating a JScrollPanel and adding to it the JTable
		JScrollPane scroll = new JScrollPane(table);
		JTable rowTable = new RowNumberTable(table);
		scroll.setRowHeaderView(rowTable);
		scroll.setCorner(JScrollPane.UPPER_LEFT_CORNER, rowTable
				.getTableHeader());

		// adding the JScrollPanel to the ContentPane
		contentPane.add(scroll, BorderLayout.CENTER);

	}

	
	/**
	 * @return The frame of the application.
	 */
	public JFrame getFrame() {
		return frame;
	}

	
	/**
	 * @return The table of the application.
	 */
	public JTable getTable() {
		return table;
	}

	
	/**
	 * @return The current sheet.
	 */
	public Sheet getSheet() {
		return sheet;
	}

	
	/**
	 * @param sheet The sheet to be set.
	 */
	public void setSheet(Sheet sheet) {
		this.sheet = sheet;
	}

	
	/**
	 * @return The stack used for the undos and the redos
	 */
	public UndoRedoStack getStack() {
		return stack;
	}

	
	/**
	 * @return The row related to the selected cell.
	 */
	public int getSelectedRow() {
		return table.getSelectedRow();
	}
	
	/**
	 * @return The rows related to the selected cells.
	 */
	public int[] getSelectedRows ()
	{
	    return table.getSelectedRows();
	}

	
	/**
	 * @return The column related to the selected cell.
	 */
	public int getSelectedColumn() {
		return table.getSelectedColumn();
	}
	
	
	/**
	 * @return The columns related to the selected cells.
	 */
	public int[] getSelectedColumns ()
	{
	    return table.getSelectedColumns();
	}

	
	/**
	 * Get the list of the column names (A, B, C ,.. AB,...) from the grid of
	 * the Sheet
	 * 
	 * @return a list of strings containing the names of the column
	 */
	private String[] getColumnNames() {
		String[] columnNames = new String[sheet.getColumns() - 1];
		for (int i = 0; i < columnNames.length; i++) {
			columnNames[i] = sheet.getGrid()[0][i + 1].getContent().toString();
		}
		return columnNames;
	}

	
	/**
	 * run the GUI application with an empty sheet
	 */
	public static void main(String[] args) {
		new JSpreadSheetGUI();
	}

    public void setTextField(JTextField textField)
    {
	   this.textField = textField;
    }

    public JTextField getTextField()
    {
	   return textField;
    }

}
